#pragma once

#include <string>
#include <chrono>
#include <atomic>
#include <optional>
#include <msgpack.hpp>
#include <random>
#include "Serializer.h"
#include "Define.h"

namespace zeroplus::mq
{

    class MessageIDGenerator
    {
    private:
        static std::atomic<uint64_t> sequence; // 自增序列
        static std::string lastTimestamp;      // 上次使用的时间戳字符串

    public:
        static std::string generate();
    };

    struct Header
    {
        std::string topic;
        std::string messageId;
        uint64_t queueId;
        uint64_t delay;
        uint64_t reconsumeTimes;
        std::string bodyType;
        MSGPACK_DEFINE(topic, messageId, queueId, delay, bodyType, reconsumeTimes);
    };

    template <typename BodyT>
    class Message
    {
    public:
        Header header_;
        std::string body_;
        MSGPACK_DEFINE(header_, body_);

    public:
        Message() = default;
        Message(std::string topic, std::string bodyType, BodyT body, uint64_t delay = 0)
        {
            header_.topic = topic;
            header_.bodyType = bodyType;
            header_.delay = delay;
            header_.reconsumeTimes = 16;
            header_.messageId = MessageIDGenerator::generate();
            header_.queueId = getRandomQueueId();
            body_ = BodyToString(body);
        }

    private:
        std::string BodyToString(const BodyT &body)
        {
            Bytes bodyBytes;
            Serializer::convert(body, bodyBytes);
            return std::move(bodyBytes.to_string());
        }
        int getRandomQueueId()
        {
            std::random_device rd;                     // 随机数生成器
            std::mt19937 gen(rd());                    // 以随机设备作为种子的梅森旋转算法生成器
            std::uniform_int_distribution<> dis(0, 9); // 定义一个在[0, 9]范围内均匀分布的整数分布
            return dis(gen);                           // 生成并返回一个随机数
        }

    public:
        void setTopic(const std::string &topic) { header_.topic = topic; }
        void setId(const std::string &messageId) { header_.messageId = messageId; }
        void setDelay(const long &delay) { header_.delay = delay; }
        void setBytes(const Bytes &bytes) { body_ = bytes.to_string(); }
        void setQueueId(const uint32_t &queueId) { header_.queueId = queueId; }

        std::string getTopic() { return header_.topic; }
        std::string getId() { return header_.messageId; }
        long getDelay() { return header_.delay; }
        Bytes getBytes() { return Bytes::from_string(body_); }
        BodyT getBody()
        {
            Bytes bytes = Bytes::from_string(body_);
            BodyT body;
            Serializer::convert(bytes, body);
            return body;
        }
        uint32_t getQueueId() { return header_.queueId; }
        Header getHeader() { return header_; }
    };

    // 特化模板类 Message，当 BodyT 为 Bytes 时
    template <>
    class Message<Bytes>
    {
    public:
        std::string messageId_; // 消息 ID
        std::string message_;   // 消息内容
        MSGPACK_DEFINE(messageId_, message_);

    public:
        Message() = default;
        Message(const std::string &id, const Bytes &message)
            : messageId_(std::move(id)), message_(std::move(message.to_string()))
        {
        }
        void setId(const std::string &id) { messageId_ = id; }
        std::string getId() const { return messageId_; }
        void setMessage(const Bytes &message) { message_ = message.to_string(); }
        Bytes getMessage() const { return Bytes::from_string(message_); }

        // 序列化 Message 对象
        Bytes getSerializeData() const
        {
            Bytes serializedData;
            Serializer::convert(*this, serializedData); // 序列化当前对象
            return serializedData;
        }

        // 反序列化 Bytes 数据为 Message 对象
        static Message<Bytes> getDeserializeData(const Bytes &serializedData)
        {
            Message<Bytes> msg;
            Serializer::convert(serializedData, msg); // 反序列化
            return msg;
        }
    };

}
